package device_center.conf.oauth2;

import cwb.consts.Oauth2Consts;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.jwt.crypto.sign.MacSigner;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;

@Configuration
@EnableResourceServer  // 开启资源服务器功能
@EnableWebSecurity  // 开启web访问安全
public class ResourceServerConfiger extends ResourceServerConfigurerAdapter {

    // jwt签名密钥
    private String sign_key =  Oauth2Consts.SIGN_KEY;


    /**
     * 该方法用于定义资源服务器向远程认证服务器发起请求，进行token校验等事宜
     *
     * @param resources
     * @throws Exception
     */
    @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
        // jwt令牌改造
        resources.resourceId("autodeliver").tokenStore(tokenStore()).stateless(true);// 无状态设置
    }

    /*
      该方法用于创建tokenStore对象（令牌存储对象）
      token以什么形式存储
   */
    public TokenStore tokenStore() {
        // 使用jwt令牌
        return new JwtTokenStore(jwtAccessTokenConverter());
    }

    /**
     * 返回jwt令牌转换器（帮助我们生成jwt令牌的）
     * 在这里，我们可以把签名密钥传递进去给转换器对象
     *
     * @return
     */
    public JwtAccessTokenConverter jwtAccessTokenConverter() {
        JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
        jwtAccessTokenConverter.setSigningKey(sign_key);  // 签名密钥
        // 资源服务器不会生产令牌，但是会校验令牌，验证时使用的密钥，和签名密钥保持一致
        jwtAccessTokenConverter.setVerifier(new MacSigner(sign_key));
        return jwtAccessTokenConverter;
    }

//    /**
//     * 该方法用于定义资源服务器向远程认证服务器发起请求，进行token校验等事宜
//     * @param resources
//     * @throws Exception
//     */
//    @Override
//    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
//
//        // 设置当前资源服务的资源id
//        resources.resourceId("autodeliver");
//        // 定义远程的token服务对象（token校验就应该靠token服务对象）向远程服务器法起请求进行校验
//        RemoteTokenServices remoteTokenServices = new RemoteTokenServices();
//        // 校验端点/接口设置（具体向那个服务器发起请求）
//        remoteTokenServices.setCheckTokenEndpointUrl("http://localhost:9999/oauth/check_token");
//        // 携带客户端id和客户端安全码
//        remoteTokenServices.setClientId("client_lagou");
//        remoteTokenServices.setClientSecret("abcxyz");
//
//        // 别忘了这一步（没有返回值，那么把new的对象放入到形参当中）
//        resources.tokenServices(remoteTokenServices);
//    }


    /**
     * 场景：一个服务中可能有很多资源（API接口）
     * 某一些API接口，需要先认证，才能访问
     * 某一些API接口，压根就不需要认证，本来就是对外开放的接口
     * 我们就需要对不同特点的接口区分对待（在当前configure方法中完成），
     * 设置是否需要经过认证
     *
     * @param http
     * @throws Exception
     */
    @Override
    public void configure(HttpSecurity http) throws Exception {
        http    // 设置session的创建策略（根据需要创建即可）
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
                // 如果要添加不同的区分认证的时候要加入这个and
                .and()
                .authorizeRequests()
                .anyRequest().permitAll();
                //匹配URL，如果匹配的话都要经过认证
//                .antMatchers("/user/**").permitAll() //特殊的放行
//                .antMatchers("/actuator/**").permitAll() //特殊的放行
//                .antMatchers("/swagger-ui.html").permitAll() //特殊的放行
//                .antMatchers("/doc.html").permitAll(); //特殊的放行
//                .anyRequest().authenticated() ; // 全部都需要认证
    }

}